#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#include <functional>

#include "log.hpp"
#include "protocol.hpp"

static const int gbacklog = 5;

enum
{
    USAGE_ERR = 1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR
};

typedef std::function<bool(const Request &req, Response &resp)> func_t;

void handlerEntery(const int sock, func_t func)
{
    std::string inbuffer;
    while (true)
    {
        // req_text是一个完整的请求，req_str是正文部分
        std::string req_text, req_str;
        // 读取: "content_len"\r\n"x op y"\r\n
        if (!recvPackage(sock, inbuffer, &req_text))
            return;
        std::cout << "带报头的请求: \n" << req_text << std::endl;

        // 截取请求中正文的部分
        if (!deLength(req_text, &req_str))
            return;
        std::cout << "去掉报头的正文: \n" << req_str << std::endl;

        // 对正文进行反序列化,得到一个结构化的请求对象
        Request req;
        if (!req.deserialize(req_str))
            return;
        // 构建一个结构化的响应
        Response resp;
        func(req, resp);

        //对响应进行序列化
        std::string resp_str;
        resp.serialize(&resp_str);
        std::cout << "计算完成，序列化的结果是: \n" << resp_str << std::endl;

        //构建一个完整的报文进行发送
        std::string send_string = enLength(resp_str);
        std::cout << "完整的响应报文是: \n" << send_string << std::endl;

        send(sock, send_string.c_str(), send_string.size(), 0);
    }
}

class CalServer
{
public:
    CalServer(const uint16_t &port)
        : _listensock(-1), _port(port) {}

    void initServer()
    {
        // 创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(FATAL, "create socket error");
            exit(SOCKET_ERR);
        }
        logMessage(NORMAL, "create socket success");

        // 设置ip和端口
        struct sockaddr_in server;
        bzero(&server, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);
        server.sin_addr.s_addr = INADDR_ANY;

        // 绑定socket和本地地址
        if (bind(_listensock, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            logMessage(FATAL, "bind socket error");
            exit(BIND_ERR);
        }
        logMessage(NORMAL, "bind socket success");

        // 设置socket位监听状态
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen socket error");
            exit(LISTEN_ERR);
        }
        logMessage(NORMAL, "listen socket success");
    }

    int start(func_t func)
    {
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 获取新连接
            int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
            if (sock < 0)
            {
                logMessage(ERROR, "accept error, continue");
                continue;
            }
            logMessage(NORMAL, "get a new link success, new socket: %d", sock);

            pid_t id = fork();
            if (id == 0)
            {
                close(_listensock);
                handlerEntery(sock, func);
                close(sock);
                exit(0);
            }
            close(sock);

            pid_t ret = waitpid(id, nullptr, 0);
            if (ret > 0)
            {
                logMessage(NORMAL, "wait child success");
            }
        }
    }

    ~CalServer() {}

private:
    int _listensock;
    uint16_t _port;
};